// MFC_OSG.cpp : implementation of the cOSG class
//
#include "stdafx.h"
#include "MFC_OSG.h"
#include <osg/ClipNode>
#include <osg/Material>
#include <osg/LightModel>


#include "../BIM_Scene_Edit.h"
//#include "MousePickHandler.h"
#include "PickHandler.h"


extern CBIM_Scene_EditApp theApp; 



cOSG::cOSG(HWND hWnd) :
   m_hWnd(hWnd) 
{
}

cOSG::~cOSG()
{
    mViewer->setDone(true);
    Sleep(1000);
    mViewer->stopThreading();

    delete mViewer;
}

void cOSG::InitOSG(std::string modelname)
{
    // Store the name of the model to load
    m_ModelName = modelname;

    // Init different parts of OSG
    InitManipulators();
    InitSceneGraph();
    InitCameraConfig();
}

void cOSG::InitManipulators(void)
{
    // Create a trackball manipulator
    trackball =  new osgGA::TrackballManipulator();

    // Create a Manipulator Switcher
    keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator();

    // Add our trackball manipulator to the switcher
    keyswitchManipulator->addMatrixManipulator( '1', "Trackball", trackball.get() );

	//int i = keyswitchManipulator->getNumMatrixManipulators();

    // Init the switcher to the first manipulator (in this case the only manipulator)
    keyswitchManipulator->selectMatrixManipulator(0);  // Zero based index Value
}


void cOSG::InitSceneGraph(void)
{
    // Init the main Root Node/Group
    mRoot = new osg::Group;

    // Load the Model from the model name
    //mModel = osgDB::readNodeFile(m_ModelName);

    //// Optimize the model
	/*osgUtil::Optimizer optimizer;
	optimizer.optimize( node.get());
	optimizer.reset();*/

    //// Add the model to the scene
    //mRoot->addChild(mModel.get());

	/*osg::ClipNode* clipGraph = new osg::ClipNode;
	mRoot->addChild( clipGraph );*/
	//SceneLayoutUtil::TestBoKunData( mRoot );

	/////////////////////////////////////////////////////////////////

	//string m_file_path = "AC11-Institute-Var-2-IFC.ifc";
	//string m_file_path = "Duplex_A_20110907.ifc";

	mRoot->addChild( theApp.GetScenePrjOSGNode().get() );


	double m_shinyness = 90.f;
	osg::ref_ptr<osg::Material> m_material_default = new osg::Material();
	/*m_material_default->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.2f, 0.25f, 0.3f, 0.3f));
	m_material_default->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0.8, 0.82, 0.84, 0.3f));
	m_material_default->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.02f, 0.025f, 0.03f, 0.03f));
	m_material_default->setShininess(osg::Material::FRONT_AND_BACK, m_shinyness);
	m_material_default->setColorMode(osg::Material::SPECULAR);
	m_material_default->setTransparency(osg::Material::FRONT_AND_BACK, 0.7f);*/
	m_material_default->setAmbient(osg::Material::FRONT, osg::Vec4f(0.8f, 0.8f,0.8f, 1.0f));
	m_material_default->setDiffuse(osg::Material::FRONT, osg::Vec4(0.6f, 0.6f,0.6f, 1.0f));
	m_material_default->setSpecular(osg::Material::FRONT, osg::Vec4f(0.3f, 0.3f,0.3f, 1.0f));
	m_material_default->setShininess(osg::Material::FRONT, m_shinyness);
	m_material_default->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE );
	m_material_default->setTransparency(osg::Material::FRONT, 0.9f);

	osg::LightModel* light_model = new osg::LightModel();
	light_model->setAmbientIntensity(osg::Vec4f(0.4f, 0.45f, 0.3f, 0.3f));
	light_model->setTwoSided( true );
	mRoot->getOrCreateStateSet()->setAttribute( light_model );

	osg::ref_ptr<osg::StateSet> m_stateset_default = theApp.GetScenePrjOSGNode()->getOrCreateStateSet();
	m_stateset_default->setAttribute( m_material_default, osg::StateAttribute::ON );

	osg::ref_ptr<osg::StateSet> m_stateset_transparent = new osg::StateSet();
	m_stateset_transparent->setAttribute(m_material_default, osg::StateAttribute::ON);
	m_stateset_transparent->setMode(GL_BLEND, osg::StateAttribute::ON);
	m_stateset_transparent->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
	m_stateset_transparent->setRenderBinDetails(11, "DepthSortedBin");



	/*osg::Material* material_selected = new osg::Material();
	material_selected->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.4f, 0.92f, 0.92f, 0.5f));
	material_selected->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.3f, 0.35f, 0.3f, 1.0f));
	material_selected->setShininess(osg::Material::FRONT_AND_BACK, m_shinyness);
	material_selected->setColorMode(osg::Material::SPECULAR);
	osg::ref_ptr<osg::StateSet> m_stateset_selected = new osg::StateSet();
	m_stateset_selected->setAttribute(material_selected, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);*/


	/////////////////////////////////////////////////////////////////
}

void cOSG::InitCameraConfig(void)
{
     // Local Variable to hold window size data
    RECT rect;

    // Create the viewer for this window
    mViewer = new osgViewer::Viewer();

    // Add a Stats Handler to the viewer
    mViewer->addEventHandler(new osgViewer::StatsHandler);
	
    
    // Get the current window size
    ::GetWindowRect(m_hWnd, &rect);

    // Init the GraphicsContext Traits
    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;

    // Init the Windata Variable that holds the handle for the Window to display OSG in.
    osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd);

    // Setup the traits parameters
    traits->x = 0;
    traits->y = 0;
    traits->width = rect.right - rect.left;
    traits->height = rect.bottom - rect.top;
    traits->windowDecoration = false;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;
    traits->setInheritedWindowPixelFormat = true;
    traits->inheritedWindowData = windata;

    // Create the Graphics Context
    osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits.get());

    // Init Master Camera for this View
    osg::ref_ptr<osg::Camera> camera = mViewer->getCamera();
	

    // Assign Graphics Context to the Camera
    camera->setGraphicsContext(gc);

    // Set the viewport for the Camera
    camera->setViewport(new osg::Viewport(traits->x, traits->y, traits->width, traits->height));

    // Set projection matrix and camera attribtues
    camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

	//camera->setClearColor(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.0f));
	camera->setClearColor(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
    camera->setProjectionMatrixAsPerspective(
        30.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0, 1000.0);

    // Add the Camera to the Viewer
    //mViewer->addSlave(camera.get());
    mViewer->setCamera(camera.get());

    // Add the Camera Manipulator to the Viewer
    mViewer->setCameraManipulator( keyswitchManipulator.get());

	mViewer->addEventHandler(new CPickHandler());

    // Set the Scene Data
    mViewer->setSceneData(mRoot.get());

    // Realize the Viewer
    mViewer->realize();

    // Correct aspect ratio
    /*double fovy,aspectRatio,z1,z2;
    mViewer->getCamera()->getProjectionMatrixAsPerspective(fovy,aspectRatio,z1,z2);
    aspectRatio=double(traits->width)/double(traits->height);
    mViewer->getCamera()->setProjectionMatrixAsPerspective(fovy,aspectRatio,z1,z2);*/
}

void cOSG::PreFrameUpdate()
{
    // Due any preframe updates in this routine
}

void cOSG::PostFrameUpdate()
{
    // Due any postframe updates in this routine
}

void cOSG::Render(void* ptr)
{
    cOSG* osg = (cOSG*)ptr;

    osgViewer::Viewer* viewer = osg->getViewer();

	//You have two options for the main viewer loop
		//viewer->run(); /*  or*/
		//while(!viewer->done()) { viewer->frame(); }

    //viewer->run();
    while(!viewer->done())
    {
        osg->PreFrameUpdate();
        viewer->frame();
        osg->PostFrameUpdate();
        //Sleep(10);         // Use this command if you need to allow other processes to have cpu time
    }

    // For some reason this has to be here to avoid issue: 
    // if you have multiple OSG windows up 
    // and you exit one then all stop rendering
    AfxMessageBox(L"Exit Rendering Thread");

    _endthread();
}